#ifndef SOCKSCONNECT_H
#define SOCKSCONNECT_H

#include "lwipstack.h"
#include "socks_client.hpp"

namespace driver2socks {

class SocksConnect
{

public:
    SocksConnect(tcp_pcb* tcp):
        tcp_(tcp),
        socks_client_(std::make_unique<SocksClient>())
    {
        using namespace std::placeholders;
        socks_client_->setErrorFunc(std::bind(&SocksConnect::onSocksError,this,_1));
        socks_client_->setRecvFunc(std::bind(&SocksConnect::send2Tcp,this,_1));
        LWIPStack::getInstance().setTcpRecvCallback(tcp_);
        LWIPStack::getInstance().setTcpSentCallback(tcp_);
        tcp_->callback_arg = this;
        tcp_nagle_disable(tcp_);
        //建立代理通道
        char remote_ip[64] = {0};
        uint32_t ip[4] = { 0 };
        if (tcp_->local_ip.type == IPADDR_TYPE_V4) {
            ip[0] = WinDivertHelperNtohl(tcp_->local_ip.u_addr.ip4.addr);
            WinDivertHelperFormatIPv4Address(ip[0], remote_ip, 64);
        } else {
            WinDivertHelperNtohIpv6Address(tcp_->local_ip.u_addr.ip6.addr, ip);
            WinDivertHelperFormatIPv6Address(ip, remote_ip, 64);
        }
        remote_host_ = remote_ip;
        remote_port_ = tcp_->local_port;
    }
    ~SocksConnect()
    {}
    void onSocksError(asio::error_code ec)
    {
        if (ec) {
            LWIPStack::getInstance().postTcpClose(tcp_);
        }
    }

    void setSocksServer(const std::string& host, const uint16_t port)
    {
        socks5_server_ip_ = host;
        socks5_server_port_ = port;
    }
    void start()
    {
        //开始socks5客户端（建立到服务器的连接并握手）
        socks_client_->start_socks(socks5_server_ip_, socks5_server_port_,
                                   remote_host_, remote_port_);
    }
    void send2Tcp(NetPacket::Ptr bf)
    {
        LWIPStack::getInstance().postTcpWrite(tcp_, bf);
    }
    bool send2Socks(NetPacket::Ptr buff)
    {
        return socks_client_->sendData(buff);
    }
    //从socks5客户端接收到的数据,等待通过pcb发送出去
    SPSCQueue<NetPacket::Ptr> queue_socks2tcp{10240};
    std::atomic_flag socks2tcp_nonfull = ATOMIC_FLAG_INIT;
    SPSCQueue<NetPacket::Ptr> queue_socks2tcp_wait_release{128};
    //即将通过pcb发送的数据
    // NetPacket::Ptr wait_send_pcb;
    //等待写入socks5客户端的数据
    SPSCQueue<NetPacket::Ptr> queue_tcp2socks{128};
    std::atomic_int32_t remaining{0};
private:
    tcp_pcb* tcp_;
    std::unique_ptr<SocksClient> socks_client_;

    std::string remote_host_;
    uint16_t remote_port_ = 0;
    std::string socks5_server_ip_;
    uint16_t socks5_server_port_;
};
}

#endif // SOCKSCONNECT_H
